#include <boost/beast/http.hpp>
#include <rapidjson/document.h>
#include <iostream>
#include <iomanip>
#include <cmath>
#include "lighter.h"
#include "signer-amd64.h"

// 构造函数 & 初始化
LighterClient::LighterClient(const std::string& config_path,
                             MARKETStruct* marketShmPtr,
                             boost::asio::io_context& ioc,
                             boost::asio::ssl::context& ssl_ctx)
    : marketShmPtr_(marketShmPtr) {
    YAML::Node yaml = YAML::LoadFile(config_path);
    config_path_ = config_path;
    const auto& lighter = yaml["lighter"];
    host_ = lighter["host"].as<std::string>();
    port_ = lighter["port"].as<std::string>();
    orderbook_depth_ = lighter["orderbook_depth"].as<int>(5);
    accountInfo_.api_key_private_key = lighter["api_key_private_key"].as<std::string>();
    accountInfo_.account_index = lighter["account_index"].as<int>();
    accountInfo_.api_key_index = lighter["api_key_index"].as<int>();

    mdConn_ = std::make_shared<WSConnection>(ioc, ssl_ctx);
    tdConn_ = std::make_shared<WSConnection>(ioc, ssl_ctx);

    httpsConnPool_ = std::make_shared<HttpsConnectionPool>(ioc, ssl_ctx, host_, port_);
    //获取orderbook信息
    if(!config_.init(httpsConnPool_)){
        std::cerr << "❌ 获取orderbook信息失败,无法订阅市场数据。" << std::endl;
        return;
    }

    CreateClient(
            const_cast<char*>("https://mainnet.zklighter.elliot.ai"),
            accountInfo_.api_key_private_key.data(),
            304,
            accountInfo_.api_key_index,
            accountInfo_.account_index);
    accountInfo_.nonce = getNextNonce();

    mdConn_->setConnectHandler([this]() {
        std::cout << "行情WS连接成功" << std::endl;
        subscribeMarkets();
        
    });
    mdConn_->setMessageHandler([this](const std::string& msg) { handleMarketMessage(msg); });
    mdConn_->setErrorHandler([](const std::string& err) {
        std::cerr << "⚠️ WS Error: " << err << std::endl;
    });

    tdConn_->setConnectHandler([this]() {
        std::cout << "✅ 交易WS连接成功" << std::endl;
        subscribeTrades();
        quantThread_ = std::thread(&LighterClient::quantLoop, this);
    });
    tdConn_->setMessageHandler([this](const std::string& msg) { handleTradeMessage(msg); });
    tdConn_->setErrorHandler([](const std::string& err) {
        std::cerr << "⚠️ 交易WS Error: " << err << std::endl;
    });
}

LighterClient::~LighterClient() {
    try {
        // 关闭 market ws 连接
        if (mdConn_) {
            mdConn_->close();
        }
        // 关闭 trade ws 连接
        if (tdConn_) {
            tdConn_->close();
        }
        // 停止下单线程
        stopQuantThread_ = true;
        // 析构前确保线程安全结束
        if (quantThread_.joinable()) {
            quantThread_.join();
        }
        printOrderBooks();
        // 3. 打印日志
        std::cout << "✅ LighterClient 析构完成，资源已释放。" << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "❌ LighterClient 析构异常: " << e.what() << std::endl;
    }
}

// 启动主循环
void LighterClient::run() {
    mdConn_->connect(host_, port_, "/stream");
    tdConn_->connect(host_, port_, "/stream");
}

// 消息处理
void LighterClient::handleMarketMessage(const std::string& msg) {
    rapidjson::Document doc;
    doc.Parse(msg.c_str());
    if (doc.HasParseError() || !doc.HasMember("type")) return;
    std::string type = doc["type"].GetString();
    if (type == "subscribed/order_book") {
        // 获取 market_id
        int market_id = -1;
        if (doc.HasMember("channel") && doc["channel"].IsString()) {
            std::string channel = doc["channel"].GetString(); // "order_book:0"
            auto pos = channel.find(':');
            if (pos != std::string::npos) {
                market_id = std::stoi(channel.substr(pos + 1));
            }
        }
        if (market_id == -1) return;
        handleOrderBookInit(market_id, doc);
    } else if (type == "update/order_book") {
        // 获取 market_id
        int market_id = -1;
        if (doc.HasMember("channel") && doc["channel"].IsString()) {
            std::string channel = doc["channel"].GetString(); // "order_book:0"
            auto pos = channel.find(':');
            if (pos != std::string::npos) {
                market_id = std::stoi(channel.substr(pos + 1));
            }
        }
        if (market_id == -1) return;
        handleOrderBookUpdate(market_id, doc);
    } else if (type == "update/account_all_trades") {
        handleAccountUpdateTrades(doc);
    }
}

void LighterClient::handleTradeMessage(const std::string& msg) {
    rapidjson::Document doc;
    doc.Parse(msg.c_str());
    if (doc.HasParseError() || !doc.HasMember("type")) return;
    std::string type = doc["type"].GetString();
    if (type == "update/account_orders") {
        handleOrdersResponse(doc);
    }
}

// 初始化 OrderBook
void LighterClient::handleOrderBookInit(int market_id, const rapidjson::Document& doc) {
    OrderBook book;
    int price_decimals = config_.marketInfoMap[market_id].price_decimals;

    const auto& ob = doc["order_book"];
    if (ob.HasMember("asks") && ob["asks"].IsArray()) {
        for (auto& a : ob["asks"].GetArray()) {
            double price = std::stod(a["price"].GetString());
            double size = std::stod(a["size"].GetString());
            long long intPrice = static_cast<long long>(price * std::pow(10, price_decimals));
            book.asks[intPrice] = size;
        }
    }
    if (ob.HasMember("bids") && ob["asks"].IsArray()) {
        for (auto& b : ob["bids"].GetArray()) {
            double price = std::stod(b["price"].GetString());
            double size = std::stod(b["size"].GetString());
            long long intPrice = static_cast<long long>(price * std::pow(10, price_decimals));
            book.bids[intPrice] = size;
        }
    }

    // 写入前 n 档卖单
    int i = 0;
    for (auto it = book.asks.begin();
        it != book.asks.end() && i < orderbook_depth_; ++it, ++i) {
        PriceLevelStruct pls{};
        pls.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER); // 假设是 ZKEX
        pls.market_id = static_cast<uint32_t>(market_id);
        pls.pl.price = it->first;
        pls.pl.size = it->second;
        pls.order_side = OrderSideEnum::ASK;
        marketShmPtr_->priceLevelShm.push(pls);
    }

    // 写入前 n 档买单
    i = 0;
    for (auto it = book.bids.begin();
         it != book.bids.end() && i < orderbook_depth_; ++it, ++i) {
        PriceLevelStruct pls{};
        pls.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);
        pls.market_id = static_cast<uint32_t>(market_id);
        pls.pl.price = it->first;
        pls.pl.size = it->second;
        pls.order_side = OrderSideEnum::BID;
        marketShmPtr_->priceLevelShm.push(pls);
    }

    orderBooks_[market_id] = std::move(book);
    std::cout << "📥 初始加载 market_id=" << market_id << std::endl;
}

// 增量更新逻辑
void LighterClient::handleOrderBookUpdate(int market_id, const rapidjson::Document& doc) {
    auto it = orderBooks_.find(market_id);
    if (it == orderBooks_.end()) return;

    OrderBook& book = it->second;
    const auto& ob = doc["order_book"];
    int price_decimals = config_.marketInfoMap[market_id].price_decimals;

    // ---- 卖盘更新 ----
    if (ob.HasMember("asks")) {
        for (auto& a : ob["asks"].GetArray()) {
            double price = std::stod(a["price"].GetString());
            double size = std::stod(a["size"].GetString());
            long long intPrice = static_cast<long long>(price * std::pow(10, price_decimals));

            if (size == 0)
                book.asks.erase(intPrice);
            else
                book.asks[intPrice] = size;

            // 获取当前第 N 档卖价
            long long sellBoundary = 0;
            int i = 0;
            for (auto it2 = book.asks.begin(); it2 != book.asks.end() && i < orderbook_depth_; ++it2, ++i)
                sellBoundary = it2->first;

            if (intPrice <= sellBoundary) {
                PriceLevelStruct pls{};
                pls.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);
                pls.market_id = market_id;
                pls.pl.price = intPrice;
                pls.pl.size = size;
                pls.order_side = OrderSideEnum::ASK;
                marketShmPtr_->priceLevelShm.push(pls);
            }

            // 额外处理 size==0：写入更新后的第 N 档
            if (size == 0 && intPrice <= sellBoundary) {
                int i = 0;
                for (auto it = book.asks.begin(); it != book.asks.end(); ++it, ++i) {
                    if (i == orderbook_depth_ - 1) { 
                        PriceLevelStruct pls{};
                        pls.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);
                        pls.market_id = static_cast<uint32_t>(market_id);
                        pls.pl.price = it->first;
                        pls.pl.size = it->second;
                        pls.order_side = OrderSideEnum::ASK;
                        marketShmPtr_->priceLevelShm.push(pls);
                        break;
                    }
                }
            }
        }
    }

    // ---- 买盘更新 ----
    if (ob.HasMember("bids")) {
        for (auto& b : ob["bids"].GetArray()) {
            double price = std::stod(b["price"].GetString());
            double size = std::stod(b["size"].GetString());
            long long intPrice = static_cast<long long>(price * std::pow(10, price_decimals));

            if (size == 0)
                book.bids.erase(intPrice);
            else
                book.bids[intPrice] = size;

            // 获取当前第 N 档买价
            long long buyBoundary = 0;
            int i = 0;
            for (auto it2 = book.bids.begin(); it2 != book.bids.end() && i < orderbook_depth_; ++it2, ++i)
                buyBoundary = it2->first;

            if (intPrice >= buyBoundary) {
                PriceLevelStruct pls{};
                pls.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);
                pls.market_id = market_id;
                pls.pl.price = intPrice;
                pls.pl.size = size;
                pls.order_side = OrderSideEnum::BID;
                marketShmPtr_->priceLevelShm.push(pls);
            }

            // 额外处理 size==0：写入更新后的第 N 档
            if (size == 0 && intPrice >= buyBoundary) {
                i = 0;
                for (auto it = book.bids.begin(); it != book.bids.end() && i < orderbook_depth_; ++it, ++i) {
                    if(i == orderbook_depth_ - 1) {
                        PriceLevelStruct pls{};
                        pls.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);
                        pls.market_id = static_cast<uint32_t>(market_id);
                        pls.pl.price = it->first;
                        pls.pl.size = it->second;
                        pls.order_side = OrderSideEnum::BID;
                        marketShmPtr_->priceLevelShm.push(pls);
                    }
                }
            }
        }
    }
}

// 订阅市场
void LighterClient::subscribeMarkets() {
    YAML::Node yaml = YAML::LoadFile(config_path_);
    const YAML::Node& lighter = yaml["lighter"];

    if (!lighter["subscribe_markets"]) {
        throw std::runtime_error("配置文件中缺少 subscribe_markets");
    }

    for (auto& sym : lighter["subscribe_markets"]) {
        std::string symbol = sym.as<std::string>();
        int market_id = config_.symbolToMarketId.count(symbol)
                            ? config_.symbolToMarketId[symbol]
                            : -1;
        if (market_id < 0) continue;

        // 订阅行情
        std::string subMarket =
            R"({"type":"subscribe","channel":"order_book/)" +
            std::to_string(market_id) + R"("})";
        mdConn_->send(subMarket);
        // 订阅账户成交
        StrOrErr createAuthTokenStrOrErr =  CreateAuthToken(0);
        std::string subTrades =
            R"({
            "type": "subscribe",
            "channel": "account_all_trades/)" + std::to_string(accountInfo_.account_index) + R"(",
            "auth": ")" + std::string(createAuthTokenStrOrErr.str) + R"("})";
        mdConn_->send(subTrades);
    }
}

void LighterClient::subscribeTrades() {
    YAML::Node yaml = YAML::LoadFile(config_path_);
    const YAML::Node& lighter = yaml["lighter"];

    if (!lighter["subscribe_markets"]) {
        throw std::runtime_error("配置文件中缺少 subscribe_markets");
    }

    for (auto& sym : lighter["subscribe_markets"]) {
        std::string symbol = sym.as<std::string>();
        int market_id = config_.symbolToMarketId.count(symbol)
                            ? config_.symbolToMarketId[symbol]
                            : -1;
        if (market_id < 0) continue;
        StrOrErr createAuthTokenStrOrErr =  CreateAuthToken(0);
        // 订阅账户订单回报
        std::ostringstream os;
        os << R"({"type":"subscribe",)"
           << R"("channel":"account_orders/)"
           << market_id << "/" << accountInfo_.account_index
           << R"(",)"
           << R"("auth":")" << createAuthTokenStrOrErr.str << R"("})";
        std::string subOrders = os.str();

        tdConn_->send(subOrders);
        std::cout << "📡 已订阅市场 " << symbol
                  << " (id=" << market_id << ")" << std::endl;
    }
}


void LighterClient::handleAccountUpdateTrades(const rapidjson::Document& doc) {
    if (!doc.HasMember("trades") || !doc["trades"].IsObject()) {
        std::cerr << "⚠️ trades 字段不存在或格式错误" << std::endl;
        return;
    }

    const auto& tradesObj = doc["trades"];
    for (auto it = tradesObj.MemberBegin(); it != tradesObj.MemberEnd(); ++it) {
        if (!it->value.IsArray()) continue;
        const auto& tradeArray = it->value.GetArray();
        for (const auto& trade : tradeArray) {
            try {
                if (!trade.IsObject()) continue;
                TradeStruct ts{};
                ts.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);

                int market_id = trade["market_id"].GetInt();
                int price_decimals = config_.marketInfoMap[market_id].price_decimals;

                ts.market_id = market_id;
                ts.trade_id = trade["trade_id"].GetUint64();
                ts.size = std::stod(trade["size"].GetString());

                double price = std::stod(trade["price"].GetString());
                ts.price = static_cast<int>(price * std::pow(10, price_decimals));

                ts.ask_id = trade["ask_id"].GetUint64();
                ts.bid_id = trade["bid_id"].GetUint64();
                ts.timestamp = trade["timestamp"].GetUint64();

                // ✅ 写入共享内存
                marketShmPtr_->tradeShm.push(ts);

                std::cout << "💹 Trade: "
                          << " market=" << ts.market_id
                          << " trade_id=" << ts.trade_id
                          << " price=" << price
                          << " size=" << ts.size
                          << " ask_id=" << ts.ask_id
                          << " bid_id=" << ts.bid_id
                          << std::endl;
            } catch (const std::exception& e) {
                std::cerr << "❌ 解析 trade 出错: " << e.what() << std::endl;
            }
        }
    }
}

void LighterClient::handleOrdersResponse(const rapidjson::Document& doc) {
    if (!doc.HasMember("orders") || !doc["orders"].IsObject()) {
        std::cerr << "⚠️ orders 字段不存在或格式错误" << std::endl;
        return;
    }
    const auto& ordersObj = doc["orders"];
    for (auto it = ordersObj.MemberBegin(); it != ordersObj.MemberEnd(); ++it) {
        if (!it->value.IsArray()) continue;
        const auto& orderArray = it->value.GetArray();
        for (const auto& order : orderArray) {
            try {
                if (!order.IsObject()) continue;
                OrderRspStruct ors{};
                ors.exchange = static_cast<uint8_t>(ExchangeEnum::LIGHTER);
                int market_id = order["market_index"].GetInt();
                int price_decimals = config_.marketInfoMap[market_id].price_decimals;

                ors.market_id = market_id;
                if(order["status"] == "open") {
                    ors.status = OrderSatusEnum::OPEN;
                } else if(order["status"] == "filled") {
                    ors.status = OrderSatusEnum::FILLED;
                } else if(order["status"] == "cancel") {
                    ors.status = OrderSatusEnum::CANCELED;
                } 
                ors.order_id = std::stoull(order["order_id"].GetString());
                ors.client_order_id = std::stoull(order["client_order_id"].GetString());
                ors.size = std::stod(order["initial_base_amount"].GetString());
                double price = std::stod(order["price"].GetString());
                ors.price = static_cast<int>(price * std::pow(10, price_decimals));
                // 写入共享内存
                marketShmPtr_->orderRspShm.push(ors);

                std::cout << "📝 Order response: "
                          << " market=" << ors.market_id
                          << " order_id=" << ors.order_id
                          << " price=" << price
                          << " size=" << ors.size
                          << " status=" << static_cast<int>(ors.status)
                          << std::endl;
            } catch (const std::exception& e) {
                std::cerr << "❌ 解析 order 出错: " << e.what() << std::endl;
            }
        }
    }
}

long long int LighterClient::getNextNonce() {
    std::string target = "/api/v1/nextNonce?account_index=" +
                         std::to_string(accountInfo_.account_index) +
                         "&api_key_index=" +
                         std::to_string(accountInfo_.api_key_index);
    std::string response = httpsConnPool_->syncSendRequest("GET", target, "", {});
    rapidjson::Document doc;
    doc.Parse(response.c_str());
    if (doc.HasParseError() || !doc.HasMember("nonce")) {
        throw std::runtime_error("获取 nonce 失败,JSON 解析错误");
    }
    long long int nonce = doc["nonce"].GetInt64();
    std::cout << "🔑 获取到初始 nonce: " << nonce << std::endl;
    return nonce;
}

void LighterClient::quantLoop() {
    size_t index = 0;

    auto makeMultipartBody = [](int tx_type, const std::string& tx_info) -> std::pair<std::string, std::vector<std::pair<std::string, std::string>>> {
        std::string boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
        std::ostringstream os;

        os << "--" << boundary << "\r\n";
        os << "Content-Disposition: form-data; name=\"tx_type\"\r\n\r\n";
        os << tx_type << "\r\n";

        os << "--" << boundary << "\r\n";
        os << "Content-Disposition: form-data; name=\"tx_info\"\r\n\r\n";
        os << tx_info << "\r\n";

        os << "--" << boundary << "--\r\n";

        std::vector<std::pair<std::string, std::string>> headers;
        headers.emplace_back("accept", "application/json");
        headers.emplace_back("content-type", "multipart/form-data; boundary=" + boundary);

        return {os.str(), headers};
    };

    while (!stopQuantThread_) {
        size_t write_index = marketShmPtr_->orderShm.next_write.load();
        while (index < write_index) {
            const auto& order = marketShmPtr_->orderShm[index];

            std::string body;
            std::vector<std::pair<std::string, std::string>> headers;

            if (order.order_type == OrderActionEnum::OPEN) {
                // 签名开单
                StrOrErr strOrErr = SignCreateOrder(
                    order.market_id,
                    order.order_id,
                    static_cast<long long int>(order.size * std::pow(10, config_.marketInfoMap[order.market_id].supported_size_decimals)),
                    order.price,
                    order.order_side == OrderSideEnum::ASK ? 1 : 0,
                    static_cast<int>(LIGHTER_ORDER_TYPE::LimitOrder),
                    static_cast<int>(LIGHTER_TIME_IN_FORCE::GoodTillTime),
                    0,
                    0,
                    -1,
                    accountInfo_.nonce++
                );
                std::cout << strOrErr.str << std::endl;
                if (strOrErr.err != nullptr) {
                    std::cerr << "❌ 签名失败: " << strOrErr.err << std::endl;
                    ++index;
                    continue;
                }

                std::tie(body, headers) = makeMultipartBody(14, strOrErr.str);
            } else {
                // 签名取消订单
                StrOrErr strOrErr = SignCancelOrder(order.market_id, order.order_id, accountInfo_.nonce++);
                if (strOrErr.err != nullptr) {
                    std::cerr << "❌ 签名失败: " << strOrErr.err << std::endl;
                    ++index;
                    continue;
                }
                std::tie(body, headers) = makeMultipartBody(15, strOrErr.str);
            }

            try {
                httpsConnPool_->asyncSendRequest("POST", "/api/v1/sendTx", body, headers,
                    [](const boost::beast::error_code& ec, const std::string& response) {
                        if (ec) {
                            std::cerr << "❌ HTTPS请求失败: " << ec.message() << std::endl;
                            return;
                        }
                        rapidjson::Document doc;
                        doc.Parse(response.c_str());

                        if (doc.HasParseError() || !doc.HasMember("code")) {
                            std::cerr << "❌ 无效响应: " << response << std::endl;
                        } else if (doc["code"].GetInt() == 200) {
                            std::cout << "✅ 下单成功: " << response << std::endl;
                        } else {
                            std::cerr << "⚠️ 下单失败 code=" << doc["code"].GetInt()
                                      << " msg=" << (doc.HasMember("message") ? doc["message"].GetString() : "")
                                      << std::endl;
                        }
                    });
            } catch (const std::exception& e) {
                std::cerr << "❌ HTTPS请求异常: " << e.what() << std::endl;
            }
            ++index;
        }
    }
}

void LighterClient::printOrderBooks() const {
    std::cout << "\n📊 lighter 当前 OrderBook 状态：" << std::endl;
    for (const auto& [mid, book] : orderBooks_) {
        std::cout << "\n--- Market " << mid << " ---\n";
        int i = 0;
        std::cout << "ASKS:\n";
        for (auto it = book.asks.begin(); it != book.asks.end() && i < orderbook_depth_; ++it, ++i)
            std::cout << "  " << i << ": price=" << it->first << " size=" << it->second << "\n";

        i = 0;
        std::cout << "BIDS:\n";
        for (auto it = book.bids.begin(); it != book.bids.end() && i < orderbook_depth_; ++it, ++i)
            std::cout << "  " << i << ": price=" << it->first << " size=" << it->second << "\n";
    }
}
